`include "../codigo/Execute.v"

module t_Execute;

    reg                 clock;
    reg                 reset;

    // Decode
    reg                 id_ex_selalushift;
    reg                 id_ex_selimregb;
    reg                 id_ex_selsarega;
    reg          [2:0]  id_ex_aluop;
    reg                 id_ex_unsig;
    reg          [1:0]  id_ex_shiftop;
    reg          [4:0]  id_ex_shiftamt;
    reg         [31:0]  id_ex_rega;
    reg          [2:0]  id_ex_msm;
    reg          [2:0]  id_ex_msl;
    reg                 id_ex_readmem;
    reg                 id_ex_writemem;
    reg                 id_ex_mshw;
    reg                 id_ex_lshw;
    reg         [31:0]  id_ex_regb;
    reg         [31:0]  id_ex_imedext;
    reg         [31:0]  id_ex_proximopc;
    reg          [2:0]  id_ex_selwsource;
    reg          [4:0]  id_ex_regdest;
    reg                 id_ex_writereg;
    reg                 id_ex_writeov;
    
    // Forwarding
    wire        [31:0]  ex_fw_wbvalue;
    wire                ex_fw_writereg;

    // Fetch
    wire                ex_if_stall;

    // Memory
    wire         [2:0]  ex_mem_msm;
    wire         [2:0]  ex_mem_msl;
    wire                ex_mem_readmem;
    wire                ex_mem_writemem;
    wire                ex_mem_mshw;
    wire                ex_mem_lshw;
    wire        [31:0]  ex_mem_regb;
    wire         [2:0]  ex_mem_selwsource;
    wire         [4:0]  ex_mem_regdest;
    wire                ex_mem_writereg;
    wire        [31:0]  ex_mem_aluout; 
    wire        [31:0]  ex_mem_wbvalue; 


    Execute execute(clock,
        reset,
        id_ex_selalushift,
        id_ex_selimregb,
        id_ex_selsarega,
        id_ex_aluop,
        id_ex_unsig,
        id_ex_shiftop,
        id_ex_shiftamt,
        id_ex_rega,
        id_ex_msm,
        id_ex_msl,
        id_ex_readmem,
        id_ex_writemem,
        id_ex_mshw,
        id_ex_lshw,
        id_ex_regb,
        id_ex_imedext,
        id_ex_proximopc,
        id_ex_selwsource,
        id_ex_regdest,
        id_ex_writereg,
        id_ex_writeov,
        ex_fw_wbvalue,
        ex_fw_writereg,
        ex_if_stall,
        ex_mem_msm,
        ex_mem_msl,
        ex_mem_readmem,
        ex_mem_writemem,
        ex_mem_mshw,
        ex_mem_lshw,
        ex_mem_regb,
        ex_mem_selwsource,
        ex_mem_regdest,
        ex_mem_writereg,
        ex_mem_aluout, 
        ex_mem_wbvalue);


    // Call tasks
    initial begin

        clock = #0 0;

        // Reset
        test_reset();

        // ALU
        test_alu_shifter();

        // Forward
        test_forward();

        // Stall
        test_stall();

        $finish;

    end


    // Clock
    always begin
        #5 clock = ~clock;
    end


    // --------------------------------------------------------------
    // Tests reset
    task test_reset;
    begin

        $display();
        reset = #0 0;
        #5;
        $display(" ------------------------------------------------");
        $display(" >>> Reset:");
        $display(" Exibe o valor dos sinais que sao enviados");
        $display(" ao estagio de memoria quando ocorre reset.\n");
        $display(" - Reset: %b;", reset);
        print_execute_mem();

        $display();
        reset = #0 1;
        #5;
        $display(" - Reset: %b;", reset);
        print_execute_mem();
        $display();

    end
    endtask


    // Prints execute_mem signs
    task print_execute_mem;
    begin

        $display(" ex_mem_msm: %b;", ex_mem_msm);
        $display(" ex_mem_msl: %b;", ex_mem_msl);
        $display(" ex_mem_readmem: %b;", ex_mem_readmem);
        $display(" ex_mem_writemem: %b;", ex_mem_writemem);
        $display(" ex_mem_mshw: %b;", ex_mem_mshw);
        $display(" ex_mem_lshw: %b;", ex_mem_lshw);
        $display(" ex_mem_regb: %b;", ex_mem_regb);
        $display(" ex_mem_selwsource: %b;", ex_mem_selwsource);
        $display(" ex_mem_regdest: %b;", ex_mem_regdest);
        $display(" ex_mem_writereg: %b;", ex_mem_writereg);
        $display(" ex_mem_aluout: %b;", ex_mem_aluout);
        $display(" ex_mem_wbvalue: %b;", ex_mem_wbvalue);

    end
    endtask


    // --------------------------------------------------------------
    // Tests ALU/shifter execution
    task test_alu_shifter; begin

        $display();
        $display(" ------------------------------------------------");
        $display(" >>> ALU / Shifter:");
        $display(" Testa operacoes na ALU/Shifter, analisando o");
        $display(" resultado obtido a partir do registrador de");
        $display(" retorno ALU/Shifter");

        $display();
        $display(" - Cycle: %d;", $time);
        print_alu();
        $display();
        print_shifter();
        $display();
        print_alu_shifter();

        $display();
        $display();
        $display(" >>> Soma:");
        id_ex_rega = #0 10;
        id_ex_regb = #0 15;
        id_ex_aluop = #0 3'b010;
        id_ex_selalushift = #0 0;
        #10;
        $display(" - Cycle: %d;", $time);
        print_alu();
        $display();
        print_shifter();
        $display();
        print_alu_shifter();

        $display();
        $display();
        $display(" >>> Shift left logic -- 5 shifts:");
        id_ex_regb = #0 2;
        id_ex_shiftop = #0 2'b10;
        id_ex_shiftamt = #0 5;
        id_ex_selalushift = #0 1;
        #10;
        $display(" - Cycle: %d;", $time);
        print_alu();
        $display();
        print_shifter();
        $display();
        print_alu_shifter();
        
        $display();

    end
    endtask

    // Prints the ALU data
    task print_alu;
    begin

        $display(" - ALU data:");
        $display(" id_ex_rega (A): %d;", id_ex_rega);
        $display(" id_ex_regb (B): %d;", id_ex_regb);
        $display(" id_ex_aluop: %b;", id_ex_aluop);
        $display(" aluout: %d;", execute.aluout);
        $display(" id_ex_unsig: %b;", id_ex_unsig);
        $display(" compout: %b;", execute.compout);
        $display(" aluov: %b;", execute.aluov);

    end
    endtask


    // Prints the shifter data
    task print_shifter;
    begin

        $display(" - Shifter data:");
        $display(" id_ex_regb (B): %b;", id_ex_regb);
        $display(" id_ex_shiftop: %b;", id_ex_shiftop);
        $display(" id_ex_shiftamt: %b;", id_ex_shiftamt);
        $display(" result: %b;", execute.result);

    end
    endtask


    // Prints the ALU/shifter data 
    task print_alu_shifter;
    begin

        $display(" - ALU(0) / Shifter(1):");
        $display(" id_ex_selalushift: %b;", id_ex_selalushift);
        $display(" mux_alusft: %b;", execute.mux_alusft);

    end
    endtask
   
    
    // --------------------------------------------------------------
    // Tests forward
    task test_forward; begin

        $display();
        $display(" ------------------------------------------------");
        $display(" >>> Forward:");
        $display(" Testa o encaminhamento de informacoes a partir");
        $display(" da analise do barramento que conecta o modulo");
        $display(" de execucao ao modulo de forward.");
        $display();
        print_writeback();
        $display();
        print_forward();
        
        id_ex_selwsource = #0 0;
        #10;
        $display();
        $display(" >>> Select mux_alusft (id_ex_selwsource = 000):");
        print_writeback();
        $display();
        print_forward();
        $display();

    end
    endtask


    // Prints the writeback data
    task print_writeback; begin

        $display(" - Writeback data:");
        $display(" mux_wbvalue: %b;", execute.mux_wbvalue);
        $display(" id_ex_selwsource: %b;", id_ex_selwsource);

    end
    endtask


    // Prints the forward data
    task print_forward; begin

        $display(" - Forward data:");
        $display(" ex_fw_wbvalue: %b;", ex_fw_wbvalue);
        $display(" ex_fw_writereg: %b;", ex_fw_writereg);

    end
    endtask



    // --------------------------------------------------------------
    // Tests stall sign
    task test_stall; begin

        $display();
        $display(" ------------------------------------------------");
        $display(" >>> Stall:");
        $display(" Testa o sinal de stall caso haja acesso a");
        $display(" memoria, seja este para leitura ou escrita");
        $display();
        print_stall();
        $display();
        print_memory();
        
        id_ex_readmem = #0 1;
        #10;
        $display();
        $display(" >>> Signs memory access as active:");
        print_stall();
        $display();
        print_memory();
        $display();

    end
    endtask


    // Prints the writeback data
    task print_stall; begin

        $display(" - Stall data:");
        $display(" ex_if_stall: %b;", ex_if_stall);

    end
    endtask


    // Prints the forward data
    task print_memory; begin

        $display(" - Memory access data:");
        $display(" id_ex_readmem: %b;", id_ex_readmem);
        $display(" id_ex_writemem: %b;", id_ex_writemem);

    end
    endtask


endmodule
